package com.maben.vue_support.interceptor;

import cn.hutool.jwt.JWTUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.maben.vue_support.constant.CommonConstant;
import com.maben.vue_support.constant.Result;
import com.maben.vue_support.util.RedisUtil;
import com.maben.vue_support.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.security.SignatureException;

@Component
@Slf4j(topic = "m.LogInterceptor")
public class LogInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        final Result result = new Result();
        //如果是OPTIONS请求 直接放行
        String method = request.getMethod();
        final String requestURI = request.getRequestURI();
        try {
            if (method.equals("OPTIONS")) {
                return true;
            }
            //从请求中获取令牌
            String jwtToken = TokenUtil.getTokenFromRequest();
            if (String.valueOf(jwtToken).equals("null")) {
                throw new SignatureException("非法的Token:" + requestURI);
            }
            //验证token
            final boolean verify = JWTUtil.verify(jwtToken, CommonConstant.TOKEN_KEY.getBytes());
            if (!verify) {
                throw new SignatureException("非法的Token::" + requestURI);
            }
            final String username = TokenUtil.getUsernameFormToken(jwtToken);
            final String redisKey = CommonConstant.REDIS_USER_HEAD + username;
            final boolean hasKey = RedisUtil.hasKey(redisKey);
            if (hasKey) {
                //验证成功后,重新刷新令牌时间
                RedisUtil.expire(redisKey, CommonConstant.REDIS_USER_TIMEOUT);
                return true;
            } else {
                result.error401("Token失效，请重新登录");
            }
        } catch (SignatureException e) {
            log.error("check token is timeout:{}", ExceptionUtils.getStackTrace(e));
            result.error401("Token超时");
        } catch (Exception e) {
            log.error("check token is error:{}", ExceptionUtils.getStackTrace(e));
            result.error500("Token 校验失败:" + e.getMessage());
        }
        responseError(response, result);
        return false;
    }

    /**
     返回错误信息
     */
    private void responseError(ServletResponse response, Result jsonResult) {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        // issues/I4YH95浏览器显示乱码问题
        httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
        OutputStream os = null;
        try {
            os = httpServletResponse.getOutputStream();
            httpServletResponse.setCharacterEncoding("UTF-8");
            httpServletResponse.setStatus(jsonResult.getCode());
            os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8"));
            os.flush();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
